import * as S3 from '@aws-sdk/client-s3';
import * as glob from "glob";
import * as fs from "fs";
import * as path from "path";
import { Readable } from "stream";
import * as qrcode from "qrcode-terminal";
import yargs from "yargs/yargs";
import { hideBin } from 'yargs/helpers';
import { FileUtils } from "./fileutils";
import { UploadAbility } from './uploadHZYX';
import { WechatCI } from './wechatCompile';
import { UnityPack } from './unityPack';
import { Time } from './time';
import { UploadAbilityEGBLU3D } from './uploadEGBLU3d';
import { CDNClientConfig, CDNClientConfigs, TCDNHost } from './CDNConfigs';
import { UploadOptions, BuildOptions, BuildPlatform, ServerType } from './CDNBuildOptions';
import { streamToString } from './lib';
import { S3CDNClient } from './S3CDNClient';
import { CDNClient } from './CDNClient';
import { AliOSSCDNClient } from './AliOSSCDNClient';
import { COSCDNClient } from './COSCDNClient';
import child_process from "child_process"


export class TCDNUploadFlowPorts {
	config!: CDNClientConfig;
	testConfig!: CDNClientConfig;
	setConfig(config: CDNClientConfig) {
		this.config = config;
	}
	setWithConfigs(configs: CDNClientConfigs) {
		if (this.serverType == "Test") {
			this.setConfig(configs.test!);
		} else if (this.serverType == "PreTest") {
			this.setConfig(configs.pretest!);
		} else {
			console.log("!!!!!!!!!!!!!! use release config !!!!!!!!!!!!!!");
			this.setConfig(configs.release!);
		}
		this.testConfig = configs.test!;
	}

	protected s3Client!: CDNClient;
	createResClient(config: CDNClientConfig): CDNClient {
		let cdnHost = config.cdnHost ?? "AliOSS"
		let s3Client;
		if (cdnHost == "S3") {
			s3Client = new S3CDNClient(config)
		} else if (cdnHost == "COS") {
			s3Client = new COSCDNClient(config)
		} else {
			s3Client = new AliOSSCDNClient(config)
		}
		return s3Client;
	}

	protected createDefaultClient() {
		let s3Client = this.createResClient(this.config);
		this.s3Client = s3Client;
		return s3Client;
	}

	getOrCreateClient() {
		if (this.s3Client) {
			return this.s3Client;
		} else {
			return this.createDefaultClient();
		}
	}

	/**
	 * 远程重新获取最新版本号
	 * @returns
	 */
	async fetchAndAddVersionCode(autoSave: boolean) {
		let config = this.config;
		let s3Client = this.createResClient(config);

		if (this.serverType == null) {
			throw new Error("invalid serverType==null")
		}
		let versionStore = this.manageVersionUrl;
		console.log("versionStore:", versionStore);

		const fetchVersionCode = async () => {
			let result = await s3Client.fetchFile(versionStore);
			let content = await streamToString(result);
			let versionCode = parseInt(content);
			return versionCode;
		};
		const saveVersionCode = async (versionCode: number) => {
			return await s3Client.uploadData(versionStore, `${versionCode}`, false);
		};
		try {
			if (!await s3Client.isExistObject(versionStore)) {
				await s3Client.uploadData(versionStore, JSON.stringify(0), false)
			}
			let versionCode0 = await fetchVersionCode();
			let versionCode = versionCode0;
			versionCode++;
			if (autoSave) {
				await saveVersionCode(versionCode);
				let versionCode2 = await fetchVersionCode();
				if (versionCode != versionCode2) {
					throw new Error(`可能存在读写冲突, 请确保没有其他人在累加版本号: R${versionCode0} -> W${versionCode} -> R${versionCode2}`);
				}
			}
			console.log("versionCode:", versionCode);
			this.versionCode = versionCode;
		} catch (err) {
			console.error("op failed: fetchAndAddVersionCode");
			throw err;
		} finally {
			s3Client.destroy();
		}
		return this.versionCode;
	}

	/**
	 * 远程获取版本号
	 * @returns
	 */
	async fetchVersionCode() {
		let s3Client = this.getOrCreateClient();
		let config = this.config;

		try {
			let result = await s3Client.fetchFile("version.txt");
			let content = await streamToString(result);
			let versionCode = parseInt(content);

			return versionCode;
		} catch (err) {
			throw err;
		}
	}

	async getCurVersion() {
		UploadAbility.setUploadDefaultConfig();
		if (this.versionCode > 0) {
			return this.versionCode;
		} else {
			return await this.fetchVersionCode();
		}
	}


	/**
	 * 获取当前版本号
	 * @returns
	 */
	async getOrFetchVersionCode() {
		console.log("getOrFetchVersionCode:" + this.buildOptions.useCustomVersionOnly);
		if (!this.buildOptions.useCustomVersionOnly) {
			if (this.versionCode > 0) {
				return this.versionCode;
			} else {
				return await this.fetchAndAddVersionCode(true);
			}
		} else {
			let versionCode = parseInt(this.buildOptions.customVersion);
			if (isNaN(versionCode)) {
				throw new Error(`invalid customVersion: ${this.buildOptions.customVersion}`);
			}
			return versionCode;
		}
	}

	/**
	 * 当前版本号
	 */
	versionCode: number = 0;
	manageVersionUrl: string = ""

	spellUploadSuffix(releasePlatform: string, versionCode: number | string, prefix: string, localDir: string | null) {
		var parts: string[] = []
		parts.push(`${this.config.downloadPath}`)
		parts.push(`/${releasePlatform}`)
		parts.push(`/${versionCode}`)
		if (prefix != null && prefix != "") {
			parts.push(`/${prefix}`)
		}
		if (localDir != null && localDir != "" && localDir != ".") {
			parts.push(`/${localDir}`)
		}
		var path = parts.join("")
		return path
	}

	async _uploadFile(s3Client: CDNClient, filepath: string, key: string, speedUp: boolean): Promise<string> {
		let config = this.config;
		try {
			var isFileExist = await s3Client.isExistObject(key)
			var canSkip = key.endsWith(".bundle")
			if (isFileExist && config.allowOverwirte == false) {
				throw new Error(`上传文件失败: 版本文件已存在, 并且不允许覆盖: ${key}`);
			} else if (isFileExist && canSkip) {
				console.log(`skip upload file exist already: ${filepath} -> ${key}`);
				return key;
			} else {
				var result = await s3Client.uploadFile(filepath, key, speedUp)
				if (isFileExist) {
					console.log(`upload-overwrite file succeed: ${filepath} -> ${key}`)
				}
				return key;
			}
		} catch (err) {
			throw err
		}
	}

	async uploadGitCommitId(client: CDNClient, suffix: string) {
		let key = `${suffix}/gitcommit-${Date.now()}.gitcommit`;
		try {
			let gitCmdline = `git log --pretty=format:\"<%H / %h> <%ci / %ai / ${new Date().toString()}> <%an@%ce> <%s> <%N>\" HEAD -1`;
			console.log(`collect git commit info: ${gitCmdline}`);
			let gitCommitInfo = child_process.execSync(gitCmdline).toString().trim();
			console.log(`upload git commit info: ${key} <= ${gitCommitInfo}`);
			await client.uploadData(key, gitCommitInfo, false);
			console.log(`upload done git commit info: ${key} <= ${gitCommitInfo}`);
			return key;
		} catch (error) {
			console.error(error);
			let msg = `git commit info unavailable`;
			console.error(msg)
			return key;
		}
	}

	protected async _upload(root: string, localDir: string, releasePlatform: string, prefix: string) {
		console.log(`upload ${process.cwd()}, ${root}, ${localDir}, ${releasePlatform}, ${prefix}`);
		let s3Client = this.getOrCreateClient();
		let config = this.config;

		root = path.resolve(root).replace(/\\/g, "/");
		var localDirAbs = path.resolve(root + '/' + localDir).replace(/\\/g, "/");

		// try {
		// 	const data = await s3Client.send(new S3.ListBucketsCommand({}));
		// 	console.log("Success", data.Buckets);
		// } catch (err) {
		// 	console.log("Error", err);
		// }
		let versionCode = await this.getOrFetchVersionCode();
		console.log("finalVersionCode:", versionCode);

		let searchPath = `${localDirAbs}/**/*`;
		console.log(`searchPath: ${searchPath}`);
		let fls = glob.sync(searchPath, {
			// root: root,
			absolute: false,
		}).filter(filepath => {
			let stat = fs.statSync(filepath);
			return !stat.isDirectory() && stat.isFile();
		});
		// console.log("fls:", fls);
		let suffix = this.spellUploadSuffix(releasePlatform, versionCode, prefix, localDir);
		console.log(`suffix: ${suffix}`)
		let uploadTasks = fls.map((filepath) => {
			let relativePath = filepath.slice(root.length);
			let key = `${suffix}/${relativePath}`.replace("//", "/");
			key = path.normalize(key).replace(/\\/g, "/");
			let speedUp = filepath.endsWith(".hash") || filepath.endsWith(".json")
			return async () => {
				console.log(`uploading file: ${filepath} -> ${key}`);
				var result = await this._uploadFile(s3Client, filepath, key, speedUp)
				console.log(`upload file success: ${relativePath} -> ${key}`);
				return result
			}
		});
		uploadTasks.unshift(() => this.uploadGitCommitId(s3Client, suffix));

		try {
			let subTasks: Promise<string>[] = [];
			// 开启 maxTaskCount 个并发数下载
			let maxTaskCount = 15;
			let it = 0;
			while (it - subTasks.length < uploadTasks.length) {
				while (subTasks.length < maxTaskCount && it < uploadTasks.length) {
					let task: Promise<string>
					try {
						task = uploadTasks[it]();
					} catch (ex) {
						task = Promise.reject(ex);
					}
					subTasks.push(task);
					++it;
					task.then(() => {
						let ii = subTasks.indexOf(task)
						if (ii >= 0) {
							subTasks.splice(ii, 1);
						}
					})
				}
				await Promise.race(subTasks);
				subTasks = subTasks.filter(s => s != null)
			}
		} catch (err) {
			throw err;
		}

		this.remoteUrl = await this.fetchDownloadUrl();
		this.remoteWebUrl = await this.fetchWebUrl();
		console.log("upload all done.\n\n");

	};


	/**
	 * 上传单个文件
	 * @param root
	 * @param localDir
	 * @param prefix
	 */
	async uploadSingleFile(root: string, filename: string) {
		console.log(`upload ${process.cwd()}, ${root}`);
		let s3Client = this.getOrCreateClient();

		root = path.resolve(root).replace(/\\/g, "/");

		let versionCode = Time.getDayDate();

		let filepath = root;

		let key = `${this.config.downloadPath}/file/${versionCode}/` + filename;
		console.log(`uploading file: ${filepath} -> ${key}`);
		let speedUp = filepath.endsWith(".hash") || filepath.endsWith(".json")
		let result = await s3Client.uploadFile(filepath, key, speedUp)
		return result;
	}

	/**
	 * 上传单个文件
	 * @param root
	 * @param localDir
	 * @param prefix
	 */
	async uploadFile(localFilePath: string, remoteFilePath: string) {
		console.log(`upload ${process.cwd()}, ${localFilePath} -> ${remoteFilePath}`);
		let s3Client = this.getOrCreateClient();

		localFilePath = path.resolve(localFilePath).replace(/\\/g, "/");

		let key = remoteFilePath;
		console.log(`uploading file: ${localFilePath} -> ${key}`);
		let speedUp = key.endsWith(".hash") || key.endsWith(".json")
		let result = await s3Client.uploadFile(localFilePath, key, speedUp)
		console.log(`uploaded file: ${localFilePath} -> ${key}`);
		return result;
	}


	/**
	 * 上传 ${root}/${localDir} 到 ${remoteUrl}/${versionCode}/${prefix}/${localDir}
	 * @param root 上传根目录
	 * @param localDir 实际上传的局部路径，本地和远程一致
	 * @param prefix 远程路径附加前缀
	 * @returns
	 */
	async upload(root: string, localDir: string, releasePlatform: string, prefix: string) {
		await this._upload(root, localDir, releasePlatform, prefix);
	}

	/**
	 * 展示上传url
	 */
	async displayUrl() {
		const url = this.remoteUrl!;

		console.log(`url: ${url}\n`);
	}

	/**
	 * 展示上传url二维码
	 */
	async displayUrlQRCode() {
		const url = this.remoteUrl!;

		await new Promise<void>((resolve, reject) => {
			qrcode.generate(url, { small: false, }, (qrcode) => {
				console.log(qrcode);
				resolve();
			});
		});
	}

	/**
	 * 展示上传url
	 */
	async displayWebUrl() {
		const url = this.remoteWebUrl!;

		console.log(`url: ${url}\n`);
		WechatCI.robotMsg("2439749", url);
	}

	/**
	 * 展示上传url二维码
	 */
	async displayWebUrlQRCode() {
		const url = this.remoteWebUrl!;

		await new Promise<void>((resolve, reject) => {
			qrcode.generate(url, { small: false, }, (qrcode) => {
				console.log(qrcode);
				resolve();
			});
		});
	}

	remoteUrl?: string;
	remoteWebUrl?: string;

	protected buildDir = "../client/build";
	setBuildDir(buildDir: string) {
		this.buildDir = buildDir;
	}

	get targetDir() {
		return `${this.buildDir}/${this.buildOptions.outputName}`;
	}

	private _localUploadDir?: string;
	public get localUploadDir(): string {
		return this._localUploadDir ?? this.buildDir;
	}
	public set localUploadDir(value: string) {
		this._localUploadDir = value;
	}

	async uploadPlatformRes({ outputName, releasePlatform, prefix }: UploadOptions) {
		if (prefix == "") {
			prefix = undefined;
		}
		await this.upload(`${this.localUploadDir}/${outputName}`, ".", releasePlatform, `${prefix ?? "hotres"}`);
	}

	buildOptions: BuildOptions = new BuildOptions();
	setBuildOptions(options: BuildOptions) {
		this.buildOptions = options;
	}
	get platform(): BuildPlatform {
		return this.buildOptions.platform as BuildPlatform;
	}
	get serverType() {
		return this.buildOptions.serverType;
	}

	/**
	 * 解析构建命令
	 */
	parseLaunchCmd(argv?: string[]) {
		console.log("parseLaunchCmd");

		const theArgv = argv ?? process.argv

		//设置服务器类型
		yargs(hideBin(theArgv))
			.command('setServer', "set server type", (yargs) => {
				return yargs.positional('server', {
					describe: "测试服",
					default: "test"
				});
			}, async (argv) => {
				await this.setServer(argv.server);
			})
			.alias("s", "server")
			.parse();

		//popo机器人发送群消息
		yargs(hideBin(theArgv))
			.command('robotMsg', "robot send message to group", (yargs) => {
				return yargs
					.positional('groupId', {
						describe: "popo群号",
						default: "2439749"
					})
					.positional("message", {
						describe: "发送消息",
						default: "无"
					});
			}, (argv) => {
				WechatCI.robotMsg(argv.groupId, argv.message);
			})
			.alias("g", "groupId")
			.alias("m", "message")
			.parse();

		//保存构建信息
		yargs(hideBin(theArgv))
			.command('saveBuildInfo', "save build info", (yargs) => {
				return yargs.positional('msg', {
					describe: "构建信息",
					default: "none"
				})
					.positional('platform', {
						describe: "构建平台",
						default: "web-mobile"
					});
			}, async (argv) => {
				await WechatCI.saveBuildInfo(argv.msg, argv.platform);
			})
			.alias("m", "msg")
			.alias("p", "platform")
			.parse();

		//unity打包
		yargs(hideBin(theArgv))
			.command('unitypack', "unity pack", (yargs) => {
				return yargs.positional('platform', {
					describe: "指定平台 可选参数window android",
					default: ""
				});

			}, async (argv) => {
				if (argv.platform == "windows") {
					UnityPack.packWindows();
				} else if (argv.platform == "android") {
					UnityPack.packAndroid();
				} else {
					console.log("no Platform set");
				}
			})
			.alias("p", "platform")
			.parse();

		// unity上传热更资源
		yargs(hideBin(theArgv))
			.command('fetchAndAddVersionCode', "fetchAndAddVersionCode", (yargs) => {
				return yargs.string('platform').demandOption("platform")
					.string("outputName").demandOption("outputName")
					.string("releasePlatform").demandOption("releasePlatform")
					.string("buildDir").demandOption("buildDir")
					.number("versionCode").demandOption("versionCode")
					.string("serverType").demandOption("serverType")
					.string("cdnAccountId").demandOption("cdnAccountId")
					.string("cdnAccountPassword").demandOption("cdnAccountPassword")
					.boolean("useCustomVersionOnly").demandOption("useCustomVersionOnly")
					.boolean("autoSave").demandOption("autoSave")
					.string("cdnConfigsPath").demandOption("cdnConfigsPath")
					.string("manageVersionUrl").demandOption("manageVersionUrl")
			}, async (argv) => {
				UploadAbilityEGBLU3D.parseCDNConfig(argv.cdnConfigsPath);
				var buildOptions = new BuildOptions();
				buildOptions.customVersion = argv.versionCode.toString();
				buildOptions.platform = argv.platform;
				buildOptions.releasePlatform = argv.releasePlatform;
				buildOptions.outputName = argv.outputName;
				buildOptions.useCustomVersionOnly = argv.useCustomVersionOnly;
				buildOptions.serverType = (argv.serverType ?? "Test") as ServerType;
				buildOptions.cdnAccountId = argv.cdnAccountId;
				buildOptions.cdnAccountPassword = argv.cdnAccountPassword;
				let autoSave = argv.autoSave
				UploadUtils.setBuildDir(argv.buildDir);
				UploadUtils.setBuildOptions(buildOptions);
				if (argv.manageVersionUrl == null || argv.manageVersionUrl == "") {
					throw new Error("invalid argv.manageVersionUrl")
				}
				UploadUtils.manageVersionUrl = argv.manageVersionUrl
				UploadAbilityEGBLU3D.setUploadDefaultConfig();
				const SetAccountInfo = (config: CDNClientConfig) => {
					config.accessKeyId = buildOptions.cdnAccountId;
					config.secretAccessKey = buildOptions.cdnAccountPassword;
				};
				SetAccountInfo(UploadAbilityEGBLU3D.configs.test!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.pretest!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.release!);
				console.log(`workDir: ${process.cwd()}`);
				await UploadAbilityEGBLU3D.fetchAndAddVersionCode(autoSave);
			})
			.parse();

		// unity上传热更资源
		yargs(hideBin(theArgv))
			.command('uu3dh', "upload u3d hot res", (yargs) => {
				return yargs.string('platform').demandOption("platform")
					.string("outputName").demandOption("outputName")
					.string("releasePlatform").demandOption("releasePlatform")
					.string("buildDir").demandOption("buildDir")
					.string("downloadPath")
					.number("versionCode").demandOption("versionCode")
					.string("serverType").demandOption("serverType")
					.string("cdnAccountId").demandOption("cdnAccountId")
					.string("cdnAccountPassword").demandOption("cdnAccountPassword")
					.boolean("useCustomVersionOnly").demandOption("useCustomVersionOnly")
					.string("cdnConfigsPath").demandOption("cdnConfigsPath");
			}, async (argv) => {
				UploadAbilityEGBLU3D.parseCDNConfig(argv.cdnConfigsPath);
				var buildOptions = new BuildOptions();
				buildOptions.customVersion = argv.versionCode.toString();
				buildOptions.platform = argv.platform;
				buildOptions.releasePlatform = argv.releasePlatform;
				buildOptions.outputName = argv.outputName;
				buildOptions.useCustomVersionOnly = argv.useCustomVersionOnly;
				buildOptions.serverType = (argv.serverType ?? "Test") as ServerType;
				buildOptions.cdnAccountId = argv.cdnAccountId;
				buildOptions.cdnAccountPassword = argv.cdnAccountPassword;
				UploadUtils.setBuildDir(argv.buildDir);
				UploadUtils.setBuildOptions(buildOptions);
				UploadAbilityEGBLU3D.setUploadDefaultConfig();
				if (argv.downloadPath != null && argv.downloadPath != '') {
					// console.log("replace downloadPath:", argv.downloadPath)
					UploadAbilityEGBLU3D.configs.test!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.pretest!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.release!.downloadPath = argv.downloadPath;
				}
				const SetAccountInfo = (config: CDNClientConfig) => {
					config.accessKeyId = buildOptions.cdnAccountId;
					config.secretAccessKey = buildOptions.cdnAccountPassword;
				};
				SetAccountInfo(UploadAbilityEGBLU3D.configs.test!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.pretest!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.release!);
				console.log(`workDir: ${process.cwd()}`);
				await UploadAbilityEGBLU3D.upload();
			})
			.parse();


		// unity上传热更资源
		yargs(hideBin(theArgv))
			.command('wechatgame', "upload u3d wechatgame", (yargs) => {
				return yargs.string('platform').demandOption("platform")
					.string("outputName").demandOption("outputName")
					.string("prefix")
					.string("releasePlatform").demandOption("releasePlatform")
					.string("buildDir").demandOption("buildDir")
					.string("downloadPath")
					.number("versionCode").demandOption("versionCode")
					.string("serverType").demandOption("serverType")
					.string("cdnAccountId").demandOption("cdnAccountId")
					.string("cdnAccountPassword").demandOption("cdnAccountPassword")
					.boolean("useCustomVersionOnly").demandOption("useCustomVersionOnly")
					.string("cdnConfigsPath").demandOption("cdnConfigsPath");
			}, async (argv) => {
				UploadAbilityEGBLU3D.parseCDNConfig(argv.cdnConfigsPath);
				var buildOptions = new BuildOptions();
				buildOptions.customVersion = argv.versionCode.toString();
				buildOptions.platform = argv.platform;
				buildOptions.releasePlatform = argv.releasePlatform;
				buildOptions.outputName = argv.outputName;
				buildOptions.prefix = argv.prefix;
				buildOptions.useCustomVersionOnly = argv.useCustomVersionOnly;
				buildOptions.serverType = (argv.serverType ?? "Test") as ServerType;
				buildOptions.cdnAccountId = argv.cdnAccountId;
				buildOptions.cdnAccountPassword = argv.cdnAccountPassword;
				UploadUtils.setBuildDir(argv.buildDir);
				UploadUtils.setBuildOptions(buildOptions);
				UploadAbilityEGBLU3D.setUploadDefaultConfig();
				if (argv.downloadPath != null && argv.downloadPath != '') {
					// console.log("replace downloadPath:", argv.downloadPath)
					UploadAbilityEGBLU3D.configs.test!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.pretest!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.release!.downloadPath = argv.downloadPath;
				}
				const SetAccountInfo = (config: CDNClientConfig) => {
					config.accessKeyId = buildOptions.cdnAccountId;
					config.secretAccessKey = buildOptions.cdnAccountPassword;
				};
				SetAccountInfo(UploadAbilityEGBLU3D.configs.test!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.pretest!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.release!);
				console.log(`workDir: ${process.cwd()}`);
				await UploadAbilityEGBLU3D.uploadWechatGame();
			})
			.parse();


		// unity上传热更资源
		yargs(hideBin(theArgv))
			.command('singlefile', "upload u3d singlefile", (yargs) => {
				return yargs
					.string("downloadPath").demandOption("downloadPath")
					.string("uploadFilePath").demandOption("uploadFilePath")
					.string("serverType").demandOption("serverType")
					.string("cdnAccountId").demandOption("cdnAccountId")
					.string("cdnAccountPassword").demandOption("cdnAccountPassword")
					.string("cdnConfigsPath").demandOption("cdnConfigsPath");
			}, async (argv) => {
				UploadAbilityEGBLU3D.parseCDNConfig(argv.cdnConfigsPath);
				var buildOptions = new BuildOptions();
				buildOptions.serverType = (argv.serverType ?? "Test") as ServerType;
				buildOptions.cdnAccountId = argv.cdnAccountId;
				buildOptions.cdnAccountPassword = argv.cdnAccountPassword;
				let downloadPath = argv.downloadPath
				let uploadFilePath = argv.uploadFilePath
				UploadUtils.setBuildOptions(buildOptions);
				UploadAbilityEGBLU3D.setUploadDefaultConfig();
				if (argv.downloadPath != null) {
					// console.log("replace downloadPath:", argv.downloadPath)
					UploadAbilityEGBLU3D.configs.test!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.pretest!.downloadPath = argv.downloadPath;
					UploadAbilityEGBLU3D.configs.release!.downloadPath = argv.downloadPath;
				}
				const SetAccountInfo = (config: CDNClientConfig) => {
					config.accessKeyId = buildOptions.cdnAccountId;
					config.secretAccessKey = buildOptions.cdnAccountPassword;
				};
				SetAccountInfo(UploadAbilityEGBLU3D.configs.test!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.pretest!);
				SetAccountInfo(UploadAbilityEGBLU3D.configs.release!);
				console.log(`workDir: ${process.cwd()}`);
				await UploadAbilityEGBLU3D.uploadSingleFile(uploadFilePath, downloadPath);
			})
			.parse();
	}

	//设置连接服务器
	async setServer(serverType: string) {
		console.log("###", serverType);

		let appendStr: string = "";
		if (serverType == "test") {
			appendStr = 'AppConfig.setTestServer()';
		} else if (serverType == "pre") {
			appendStr = 'AppConfig.setPreServer()';
		} else if (serverType == "format") {
			appendStr = 'AppConfig.setFormatServer()';
		}

		console.log("###path##", process.cwd());

		let filepath = "../client/assets/script/configs/AppConfig.ts";
		let fileContent = fs.readFileSync(filepath, "utf-8");

		const r = /AppConfig\.set(\S)*Server\(\)/g;
		if (r.test(fileContent)) {
			fileContent = fileContent.replace(r, appendStr);
			console.log(fileContent);
		} else {
			fileContent = fileContent + `\n${appendStr}\n`;
			console.log(fileContent);
		}

		await fs.writeFileSync(filepath, fileContent, "utf-8");
	}



	/**
	 * 执行上传
	 */
	async uploadPlatformFolder() {
		await this.uploadPlatformRes(this.buildOptions);
	}

	/**
	 * 获取下载链接
	 * @returns
	 */
	async fetchDownloadUrl() {
		let config = this.config;
		let versionCode = await this.getOrFetchVersionCode();

		let suffix = this.spellUploadSuffix(this.platform, versionCode, `hotres`, null);
		let url = `${config.downloadUrl}/${suffix}/`;
		return url;
	}

	/**
	 * 获取下载链接
	 * @returns
	 */
	async fetchWebUrl() {
		let downloadUrl = await this.fetchDownloadUrl();
		let url = `${downloadUrl}index.html`;
		return url;
	}

	/**
	 * 获取下载链接
	 * @deprecated
	 * @returns
	 */
	protected async fetchInsiderUrl() {
		let config = this.config;
		let versionCode = await this.getOrFetchVersionCode();

		let suffix = this.spellUploadSuffix(this.platform, versionCode, `hotres`, null);
		let url = `http://${config.bucket}.s3-website.${config.region}.amazonaws.com.cn/${suffix}/index.html`;
		return url;
	}

	/**
	 * 删除配置为远程加载的目录
	 * @returns
	 */
	removeRemoteFolders() {
		return Promise.all([
			FileUtils.removeFolder("remote"),
		]);
	}

}

export const UploadUtils = new TCDNUploadFlowPorts()
